package org.tech4j.edi.base.retry;

import com.google.common.base.Throwables;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tech4j.edi.api.context.RetryContext;
import org.tech4j.edi.api.context.RetryContextService;
import org.tech4j.edi.base.exception.BizSuccessException;
import org.tech4j.edi.common.RetryHandle;
import org.tech4j.edi.common.constant.EdiConstants;
import org.tech4j.edi.common.entity.RetryBizConfig;
import org.tech4j.edi.common.entity.RetryBizRecord;
import org.tech4j.edi.common.enums.RetryStatusEnum;
import org.tech4j.edi.persistence.api.RetryRecordPersistService;

import java.util.Date;

/**
 * @program: tech4j
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/7 20:13
 **/
public class DefaultRetryContextService implements RetryContextService {
    private static final Logger log = LoggerFactory.getLogger(DefaultRetryContextService.class);
    private final RetryRecordPersistService retryRecordPersistService;

    public DefaultRetryContextService(RetryRecordPersistService retryRecordPersistService) {
        this.retryRecordPersistService = retryRecordPersistService;
    }

    @Override
    public void retry(RetryContext context) {
        RetryBizRecord retryBizRecord = context.getRetryBizRecord();
        updateRetryRecordStatus(retryBizRecord, RetryStatusEnum.RETRY_ING);
        RetryStatusEnum retryStatus = RetryStatusEnum.RETRY_SUCCESS;
        RetryHandle retryHandle = context.getRetryHandle();
        RetryBizConfig retryBizConfig = context.getRetryBizConfig();
        try {
            retryHandle.doRetry(retryBizRecord.getBizParams());
        } catch (BizSuccessException successException) {
            log.warn("DefaultRetryContextService[retry] failed with BizSuccessException, but the final status is success");
            setErrorMessage(retryBizRecord, Throwables.getStackTraceAsString(successException));
        } catch (Throwable e) {
            retryStatus = RetryStatusEnum.RETRY_FAIL;
        }
        retryBizRecord.setLastOpTime(new Date());
        Integer retryTimes = retryBizRecord.getAndAddRetryTimes();
        if (retryTimes >= retryBizConfig.getMaxRetryTimes()) {
            retryStatus = RetryStatusEnum.RETRY_STOP;
        }
        retryBizRecord.setRecordStatus(retryStatus);
        updateRetryRecordStatus(retryBizRecord, retryStatus);
    }

    private void updateRetryRecordStatus(RetryBizRecord retryBizRecord, RetryStatusEnum statusEnum) {
        retryRecordPersistService.updateRetryStatus(retryBizRecord, statusEnum);
    }

    public void setErrorMessage(RetryBizRecord retryBizRecord, String errorMessage) {
        if (StringUtils.length(errorMessage) > EdiConstants.RETRY_RECORD_MAX_ERROR_MESSAGE_LENGTH) {
            errorMessage = StringUtils.substring(errorMessage, 0, EdiConstants.RETRY_RECORD_MAX_ERROR_MESSAGE_LENGTH);
        }
        retryBizRecord.setErrorMessage(errorMessage);
    }
}
